const jwt = require('jsonwebtoken')
const config = require('../config')
const User = require('../models/User')
const { HTTP_STATUS, ERROR_CODES, USER_ROLES } = require('../utils/constants')
const logger = require('../utils/logger')

/**
 * JWT令牌验证中间件
 */
const authenticateToken = async (req, res, next) => {
  try {
    const authHeader = req.headers['authorization']
    const token = authHeader && authHeader.split(' ')[1] // Bearer TOKEN

    if (!token) {
      return res.status(HTTP_STATUS.UNAUTHORIZED).json({
        success: false,
        error: {
          code: ERROR_CODES.TOKEN_MISSING,
          message: '访问令牌缺失'
        }
      })
    }

    // 验证令牌
    const decoded = jwt.verify(token, config.jwt.secret)
    
    // 获取用户信息
    const user = await User.findByPk(decoded.userId)
    
    if (!user) {
      return res.status(HTTP_STATUS.UNAUTHORIZED).json({
        success: false,
        error: {
          code: ERROR_CODES.USER_NOT_FOUND,
          message: '用户不存在'
        }
      })
    }

    // 检查用户是否被禁用
    if (user.isActive === false) {
      return res.status(HTTP_STATUS.FORBIDDEN).json({
        success: false,
        error: {
          code: ERROR_CODES.USER_DISABLED,
          message: '用户账户已被禁用'
        }
      })
    }

    // 检查用户是否被删除
    if (user.isDeleted) {
      return res.status(HTTP_STATUS.FORBIDDEN).json({
        success: false,
        error: {
          code: ERROR_CODES.USER_DELETED,
          message: '用户账户已被删除'
        }
      })
    }

    // 将用户信息添加到请求对象
    req.user = User.sanitizeUser(user)
    req.token = token

    logger.logAuth('Token authenticated', user.id, true, {
      username: user.username,
      role: user.role,
      ip: req.ip,
      userAgent: req.get('User-Agent')
    })

    next()
  } catch (error) {
    if (error.name === 'JsonWebTokenError') {
      return res.status(HTTP_STATUS.UNAUTHORIZED).json({
        success: false,
        error: {
          code: ERROR_CODES.TOKEN_INVALID,
          message: '无效的访问令牌'
        }
      })
    }

    if (error.name === 'TokenExpiredError') {
      return res.status(HTTP_STATUS.UNAUTHORIZED).json({
        success: false,
        error: {
          code: ERROR_CODES.TOKEN_EXPIRED,
          message: '访问令牌已过期'
        }
      })
    }

    logger.error('Authentication error', {
      error: error.message,
      stack: error.stack,
      ip: req.ip
    })

    return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({
      success: false,
      error: {
        code: ERROR_CODES.INTERNAL_ERROR,
        message: '认证过程中发生错误'
      }
    })
  }
}

/**
 * 可选的JWT令牌验证中间件（令牌可选）
 */
const optionalAuth = async (req, res, next) => {
  try {
    const authHeader = req.headers['authorization']
    const token = authHeader && authHeader.split(' ')[1]

    if (!token) {
      // 没有令牌，继续执行但不设置用户信息
      return next()
    }

    // 有令牌，尝试验证
    const decoded = jwt.verify(token, config.jwt.secret)
    const user = await User.findByPk(decoded.userId)
    
    if (user && user.isActive !== false && !user.isDeleted) {
      req.user = User.sanitizeUser(user)
      req.token = token
    }

    next()
  } catch (error) {
    // 令牌验证失败，但继续执行（不设置用户信息）
    next()
  }
}

/**
 * 角色权限验证中间件工厂
 */
const requireRole = (requiredRoles) => {
  return (req, res, next) => {
    if (!req.user) {
      return res.status(HTTP_STATUS.UNAUTHORIZED).json({
        success: false,
        error: {
          code: ERROR_CODES.AUTHENTICATION_REQUIRED,
          message: '需要身份验证'
        }
      })
    }

    // 支持单个角色或角色数组
    const roles = Array.isArray(requiredRoles) ? requiredRoles : [requiredRoles]
    const hasPermission = roles.some(role => User.hasPermission(req.user, role))

    if (!hasPermission) {
      logger.logSecurity('Access denied - insufficient permissions', {
        userId: req.user.id,
        userRole: req.user.role,
        requiredRoles: roles,
        ip: req.ip,
        path: req.path
      })

      return res.status(HTTP_STATUS.FORBIDDEN).json({
        success: false,
        error: {
          code: ERROR_CODES.INSUFFICIENT_PERMISSIONS,
          message: '权限不足'
        }
      })
    }

    next()
  }
}

/**
 * 管理员权限验证中间件
 */
const requireAdmin = requireRole(USER_ROLES.ADMIN)

/**
 * 学生权限验证中间件
 */
const requireStudent = requireRole(USER_ROLES.STUDENT)

/**
 * 资源所有者验证中间件工厂
 */
const requireOwnership = (resourceIdParam = 'id', userIdField = 'userId') => {
  return async (req, res, next) => {
    if (!req.user) {
      return res.status(HTTP_STATUS.UNAUTHORIZED).json({
        success: false,
        error: {
          code: ERROR_CODES.AUTHENTICATION_REQUIRED,
          message: '需要身份验证'
        }
      })
    }

    // 管理员可以访问所有资源
    if (User.isAdmin(req.user)) {
      return next()
    }

    const resourceId = req.params[resourceIdParam]
    
    if (!resourceId) {
      return res.status(HTTP_STATUS.BAD_REQUEST).json({
        success: false,
        error: {
          code: ERROR_CODES.INVALID_REQUEST,
          message: '资源ID缺失'
        }
      })
    }

    // 这里需要根据具体的资源类型来验证所有权
    // 由于我们使用的是通用中间件，这里只是示例
    // 实际使用时需要在具体的路由中进行更详细的验证
    
    next()
  }
}

/**
 * 会话所有者验证中间件
 */
const requireSessionOwnership = async (req, res, next) => {
  if (!req.user) {
    return res.status(HTTP_STATUS.UNAUTHORIZED).json({
      success: false,
      error: {
        code: ERROR_CODES.AUTHENTICATION_REQUIRED,
        message: '需要身份验证'
      }
    })
  }

  // 管理员可以访问所有会话
  if (User.isAdmin(req.user)) {
    return next()
  }

  const sessionId = req.params.sessionId || req.params.id
  
  if (!sessionId) {
    return res.status(HTTP_STATUS.BAD_REQUEST).json({
      success: false,
      error: {
        code: ERROR_CODES.INVALID_REQUEST,
        message: '会话ID缺失'
      }
    })
  }

  try {
    const ChatSession = require('../models/ChatSession')
    const session = await ChatSession.findByPk(sessionId)
    
    if (!session) {
      return res.status(HTTP_STATUS.NOT_FOUND).json({
        success: false,
        error: {
          code: ERROR_CODES.SESSION_NOT_FOUND,
          message: '会话不存在'
        }
      })
    }

    if (session.userId !== req.user.id) {
      logger.logSecurity('Access denied - session ownership', {
        userId: req.user.id,
        sessionId,
        sessionOwnerId: session.userId,
        ip: req.ip
      })

      return res.status(HTTP_STATUS.FORBIDDEN).json({
        success: false,
        error: {
          code: ERROR_CODES.ACCESS_DENIED,
          message: '无权访问此会话'
        }
      })
    }

    req.session = session
    next()
  } catch (error) {
    logger.error('Session ownership verification error', {
      error: error.message,
      sessionId,
      userId: req.user.id
    })

    return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({
      success: false,
      error: {
        code: ERROR_CODES.INTERNAL_ERROR,
        message: '验证会话所有权时发生错误'
      }
    })
  }
}

/**
 * AI配置所有者验证中间件
 */
const requireConfigOwnership = async (req, res, next) => {
  if (!req.user) {
    return res.status(HTTP_STATUS.UNAUTHORIZED).json({
      success: false,
      error: {
        code: ERROR_CODES.AUTHENTICATION_REQUIRED,
        message: '需要身份验证'
      }
    })
  }

  // 管理员可以访问所有配置
  if (User.isAdmin(req.user)) {
    return next()
  }

  const configId = req.params.configId || req.params.id
  
  if (!configId) {
    return res.status(HTTP_STATUS.BAD_REQUEST).json({
      success: false,
      error: {
        code: ERROR_CODES.INVALID_REQUEST,
        message: '配置ID缺失'
      }
    })
  }

  try {
    const AiConfig = require('../models/AiConfig')
    const config = await AiConfig.findByPk(configId)
    
    if (!config) {
      return res.status(HTTP_STATUS.NOT_FOUND).json({
        success: false,
        error: {
          code: ERROR_CODES.CONFIG_NOT_FOUND,
          message: 'AI配置不存在'
        }
      })
    }

    if (config.userId !== req.user.id) {
      logger.logSecurity('Access denied - config ownership', {
        userId: req.user.id,
        configId,
        configOwnerId: config.userId,
        ip: req.ip
      })

      return res.status(HTTP_STATUS.FORBIDDEN).json({
        success: false,
        error: {
          code: ERROR_CODES.ACCESS_DENIED,
          message: '无权访问此配置'
        }
      })
    }

    req.aiConfig = config
    next()
  } catch (error) {
    logger.error('Config ownership verification error', {
      error: error.message,
      configId,
      userId: req.user.id
    })

    return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({
      success: false,
      error: {
        code: ERROR_CODES.INTERNAL_ERROR,
        message: '验证配置所有权时发生错误'
      }
    })
  }
}

/**
 * 刷新令牌验证中间件
 */
const authenticateRefreshToken = async (req, res, next) => {
  try {
    const { refreshToken } = req.body

    if (!refreshToken) {
      return res.status(HTTP_STATUS.UNAUTHORIZED).json({
        success: false,
        error: {
          code: ERROR_CODES.REFRESH_TOKEN_MISSING,
          message: '刷新令牌缺失'
        }
      })
    }

    // 验证刷新令牌
    const decoded = jwt.verify(refreshToken, config.jwt.refreshSecret)
    
    // 获取用户信息
    const user = await User.findByPk(decoded.userId)
    
    if (!user || user.isActive === false || user.isDeleted) {
      return res.status(HTTP_STATUS.UNAUTHORIZED).json({
        success: false,
        error: {
          code: ERROR_CODES.INVALID_REFRESH_TOKEN,
          message: '无效的刷新令牌'
        }
      })
    }

    req.user = User.sanitizeUser(user)
    req.refreshToken = refreshToken

    next()
  } catch (error) {
    if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') {
      return res.status(HTTP_STATUS.UNAUTHORIZED).json({
        success: false,
        error: {
          code: ERROR_CODES.INVALID_REFRESH_TOKEN,
          message: '无效或过期的刷新令牌'
        }
      })
    }

    logger.error('Refresh token authentication error', {
      error: error.message,
      ip: req.ip
    })

    return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({
      success: false,
      error: {
        code: ERROR_CODES.INTERNAL_ERROR,
        message: '刷新令牌验证过程中发生错误'
      }
    })
  }
}

module.exports = {
  authenticateToken,
  optionalAuth,
  requireRole,
  requireAdmin,
  requireStudent,
  requireOwnership,
  requireSessionOwnership,
  requireConfigOwnership,
  authenticateRefreshToken
}